#include <iostream>

using namespace std;

//虚析构和纯虚析构
//多态使用时，如果子类中有属性开辟到堆区，那么父类指针在释放时无法调用到子类的析构代码
//解决方式：将父类中的析构函数改为虚析构或者纯虚析构
//虚析构和纯虚析构共性：可以解决父类指针释放子类对象，都需要有具体的函数实现
//虚析构和纯虚析构区别：如果是纯虚析构，该类属于抽象类，无法实例化对象
//虚析构语法：
//virtual ~类名(){}
//纯虚析构语法：
//virtual ~类名() = 0;
//类名::~类名(){}
class Animal {
public:
    string *name;

    Animal() {
        cout << "Animal构造函数调用！" << endl;
    }

    virtual void speak() = 0;//纯虚函数
    //利用虚析构可以解决 父类指针释放子类对象时不干净的问题
//    virtual ~Animal() {
//        cout << "Animal虚析构函数调用！" << endl;
//    }
//};
    //有了纯虚析构之后，这个类也属于抽象类，无法实例化对象 需要声明也需要实现
    virtual ~Animal() = 0;//纯虚析构
};

Animal::~Animal() {
    cout << "Animal 纯虚析构函数调用！" << endl;
}

class Cat : public Animal {
public:
    Cat(string name) {
        cout << "Cat构造函数调用！" << endl;
        this->name = new string(name);
    }

    void speak() {
        cout << *this->name << "小猫在说话!" << endl;
    }

    ~Cat() {
        cout << "Cat析构函数调用!" << endl;
        if (this->name != nullptr) {
            delete name;
            name = nullptr;
        }
    }
};

void test1() {
    Animal *animal = new Cat("Tom");
    animal->speak();
    //父类在指针在析构的时候 不会调用子类中的析构函数，导致子类如果有堆区属性，会出现内存泄漏
    delete animal;
}

int main() {
    test1();
    return 0;
}